// Copyright (c) 2021 Presto Labs Pte. Ltd.
// Author: daniel

#include "coin2/exchange/gateio/api_order/native_rest_async_asio_subscriber.h"

#include <glog/logging.h>

#include "coin2/exchange/gateio/api_order/native_private_client.h"
#include "coin2/exchange/order/gateio.pb.h"

namespace coin2::exchange::gateio::api_order {

void GateioRestAsyncAsioSubscriber::QueryBalance() {
  auto http_context = rest_client()->QueryAccountBalance();
  if (!http_context) {
    return;
  }
  http_context->handler =
      std::bind(&GateioRestAsyncAsioSubscriber::HandleQuery, this, std::placeholders::_1);
  http_driver_->PostAsyncContext(http_context);
}

void GateioRestAsyncAsioSubscriber::QueryOpenOrders(int page) {
  RestParams params;
  params.set_page(std::to_string(page));
  auto http_context = rest_client()->QueryOpenOrders(params);
  if (!http_context) {
    return;
  }
  http_context->handler =
      std::bind(&GateioRestAsyncAsioSubscriber::HandleQuery, this, std::placeholders::_1);
  http_driver_->PostAsyncContext(http_context);
}

void GateioRestAsyncAsioSubscriber::QueryHistOrders(const std::string& native_symbol) {
  RestParams params;
  params.set_currency_pair(native_symbol);
  auto http_context = rest_client()->QueryHistOrders(params);
  if (!http_context) {
    return;
  }
  http_context->handler =
      std::bind(&GateioRestAsyncAsioSubscriber::HandleQuery, this, std::placeholders::_1);
  http_driver_->PostAsyncContext(http_context);
}

void GateioRestAsyncAsioSubscriber::QueryTransfer() {
  RestParams params;
  auto http_context = rest_client()->QueryDeposit(params);
  if (!http_context) {
    return;
  }
  http_context->handler =
      std::bind(&GateioRestAsyncAsioSubscriber::HandleQuery, this, std::placeholders::_1);
  http_driver_->PostAsyncContext(http_context);

  http_context = rest_client()->QueryWithdrawal(params);
  if (!http_context) {
    return;
  }
  http_context->handler =
      std::bind(&GateioRestAsyncAsioSubscriber::HandleQuery, this, std::placeholders::_1);
  http_driver_->PostAsyncContext(http_context);

  http_context = rest_client()->QueryTransfers(params);
  if (!http_context) {
    return;
  }
  http_context->handler =
      std::bind(&GateioRestAsyncAsioSubscriber::HandleQuery, this, std::placeholders::_1);
  http_driver_->PostAsyncContext(http_context);
}

void GateioRestAsyncAsioSubscriber::QueryHistTrades(const std::string& native_symbol) {
  RestParams params;
  params.set_currency_pair(native_symbol);
  auto http_context = rest_client()->QueryHistTrades(params);
  if (!http_context) {
    return;
  }
  http_context->handler =
      std::bind(&GateioRestAsyncAsioSubscriber::HandleQuery, this, std::placeholders::_1);
  http_driver_->PostAsyncContext(http_context);
}

void GateioRestAsyncAsioSubscriber::SubscribeAsync() {
  AddPeriodicTask(
      std::bind(&GateioRestAsyncAsioSubscriber::QueryBalance, this),
      config_.query_account_balance_period_sec(),
      "query_balance");

  auto* client = static_cast<GateioNativePrivateClient*>(rest_client());
  if (is_readonly_order_system_ && symcache_->is_spot() && client->IsMasterAccount()) {
    AddPeriodicTask(
        std::bind(&GateioRestAsyncAsioSubscriber::QueryTransfer, this),
        config_.query_account_balance_period_sec(),
        "query_transfer");
    return;
  }

  AddPeriodicTask(
      std::bind(&GateioRestAsyncAsioSubscriber::QueryOpenOrders, this, 1),
      config_.query_open_orders_period_sec(),
      "query_open_orders");

  const auto symbol_list = native_symbols();

  AddPeriodicTask(
      std::bind(&GateioRestAsyncAsioSubscriber::QueryHistOrders, this, std::placeholders::_1),
      std::bind(
          &GateioRestAsyncAsioSubscriber::SkipQuery,
          this,
          "query_history_orders",
          std::placeholders::_1),
      config_.query_cancel_orders_period_sec(),
      "query_history_orders",
      symbol_list);

  AddPeriodicTask(
      std::bind(&GateioRestAsyncAsioSubscriber::QueryHistTrades, this, std::placeholders::_1),
      std::bind(
          &GateioRestAsyncAsioSubscriber::SkipQuery,
          this,
          "query_fills",
          std::placeholders::_1),
      config_.query_fill_period_sec(),
      "query_fills",
      symbol_list);

  // handle number of open order more than 100
  mb_->Subscribe("gateio_spot/query_open_orders", [this](const std::string&, void* data) {
    int limit = 100;
    int total = *(reinterpret_cast<int*>(data));
    if (total <= limit) {
      return;
    }
    int page = 2;
    total -= limit;
    while (total > 0) {
      this->QueryOpenOrders(page);
      total -= limit;
      ++page;
    }
  });
}

}  // namespace coin2::exchange::gateio::api_order
